import { CommunitSingleton } from './CommunitSingleton'
import { Community } from './Community'
import HashMap from '@ohos.util.HashMap';
// 数据库工具，初始化
import DatabaseUtil from "./utils/DatabaseUtil"

import WeightConfigMapper from "./mapper/WeightConfigMapper"

type gramListener = (gram: number) => void;
/**
 * 简介：用于将从物理传感器获取的数据进行二次封装，可以直接拿到真实数据
 * @author an-ran0
 */
export class WeightUtil {
  /**
   * 全局单例对象
   */
  private static weightUtil: WeightUtil;

  /**
   * 获取单例对象
   * @returns
   */
  public static getInstance() {

    if (this.weightUtil)
      return WeightUtil.weightUtil;
    this.weightUtil = new WeightUtil();
    return WeightUtil.weightUtil
  }


  /**
   * 用于存放真实数据的接口
   */
  private community: Community;
  /**
   * 放置所有监听状态变化的监听器
   */
  private weightUpListenerMap: HashMap<any, gramListener> = new HashMap();
  /**
   * 重量的历史数据
   */
  private weightDataArray: Array<number> = [];
  /**
   * 用于缓冲历史数据的长短
   */
  public weightDataArraySize: number = 5;
  /**
   * 补偿值数据、用于校零
   */
  public offset: number = 0;
  /**
   *  比率 = 补偿后的原始数据/克
   */
  public ratio = 1;
  /**
   * 原始数据
   */
  private weight = 0;
  /**
   * 数据是否稳定的标志
   *
   * 当 weightDataArray 最大值与最小值的差小于stabilizeFlag时判断为质量稳定
   */
  public stabilizeFlag = 10;


  /**
   * 全局数据初始化如果不进行初始化会爆炸
   */
  public init(context) {
    // 初始化数据库
    DatabaseUtil.initWeightConfigPreferences(context, () => {


      // 初始化相关数据
      WeightConfigMapper.getOffSet().then((v: number) => {
        this.offset = v;
      })
      WeightConfigMapper.getRatio().then((v: number) => {
        this.ratio = v;
      })
    })


    this.community = CommunitSingleton.getInstance();

    // 初始化监听器
    this.community.setWeightListener(this.weightListener)


  }
  /**
   * 用于监听真实数据的监听器
   * @param 真实数据
   */
  private weightListener = (weight: number) => {
    // 更新本地的原始重量
    this.weight = weight;

    // 将最新数据添加到数据列表，如果内容超出，那么删除头数据
    if (this.offset != 0 && this.ratio != 1) //只有已经校秤过的数据才加入数据列表
      this.weightDataArray.push(this.getGram())

    if (this.weightDataArray.length > this.weightDataArraySize)
      this.weightDataArray.shift();

    // console.log(`anran weightListener ${this.weightUpListenerMap.length} ${weight}`);

    // 响应所有监听器
    this.weightUpListenerMap.forEach((value) => {
      value(this.getGram());
    })
  }

  /**
   * 添加监听器
   * @param key 监听器的唯一标识
   * @param listener 监听器
   */
  public addListener(key: any, listener: gramListener) {
    this.weightUpListenerMap.set(key, listener)
  }
  /**
   * 移除监听器
   * @param key
   */
  public removeListener(key: any) {
    this.weightUpListenerMap.remove(key);
  }
  /**
   * 校准
   * @param gram 所承受的物理克数
   */
  public calibration(gram): void {
    this.ratio = this.getCWeight() / gram;
    WeightConfigMapper.PutRatio(this.ratio);
  }
  /**
   * 数据清零
   */
  public clear() {
    // 将当前重量作为基准值
    this.offset = this.weight;
    WeightConfigMapper.putOffSet(this.offset);


  }
  /**
   * 获取从传感器得到的真实数据
   * @returns
   */
  public getWeight(): number {
    return this.weight
  }
  /**
   * 获取补偿过的真实数据
   * @returns
   */
  public getCWeight(): number {
    return this.getWeight() - this.offset;
  }
  /**
   * 获取传感器上产品的克数
   * @returns
   */
  public getGram(): number {
    let gram = (this.getCWeight() / this.ratio).toFixed(0);
    return parseFloat(gram);
  }
  /**
   *用来判断数据是否稳定
   * @returns true-数据稳定 false-数据不稳定
   */
  public isStabilize(): boolean {
    let min: number = null, max: number = null;
    // 擂台法获得最大值和最小值u
    this.weightDataArray.forEach((value) => {
      // 当数据为空时那么数据本身就是最大值最小值
      if (min == null || min == null) {
        max = min = value;
      } else {
        max = max > value ? max : value;
        min = min < value ? min : value;
      }
    })
    // 如果最大值与最小值的够小，那么就是稳定数据
    if (max != null && min != null)
      return (max - min) > this.stabilizeFlag;
    else
      return false;
  }
}